#lang scheme

(define % remainder)
(define // quotient)

(define (pow a b)                                                ; функция степени
  (if ( = b 0) 1 (* a (pow a (- b 1)))))


(define (func1 num)                                              ; геометрическая прогрессия
  (define (iter num a q)                                         ; num - число, а - первый элемент, q - коэффицент прогрессии
    (if (= num 0)                                                ; база рекурсии
        #t
        (if (and (not (= (% num 10) 0)) (= ( / (% num 10) a) q)) ; проверка числа на ноль и на равенство q и отношение первого ко второму элементов
            (iter (// num 10) (% num 10) q)
            #f
  )))
  (if (= (% num 10) 0)                                           ; 0 < num < 10
      #f
      (iter (// num 10) (% num 10) (/ (% (// num 10) 10) (% num 10)))))
      
(define (func2 num)                                              ; арифметическая прогрессия
  (define (iter num a b)
    (if (= num 0)                                                ; база рекурсии
        #t
        (if (= b (- (% num 10) a))                               ; разность первого и второго элемента совпадает с b
            (iter (// num 10) (% num 10) b)
            #f
  )))
  (iter (// num 10) (% num 10) (- (% (// num 10) 10) (% num 10))))
               
(define (z1 num)
  (or (func1 num) (func2 num)))                                  ; является ли какой-нибудь прогрессией

;-------------------------------------------------------------------------


(define (count-digit num)                                    ; считает кол-во разрядов числа
  (if (< num 10)
      (if (= num 0) 0 1 )
      (+ 1 (count-digit (// num 10)))))

(define (find-highest-seq seq)                               ; находим большую последовательность 
  (define (iter num a b)                                     ; num - остаточное число, a и b - первый и второй разряды числа (справа)
    (if (= 0 num)                                            ; база
        seq                                                  ; возвращаем возрастающую большую последовательность
        (if (> a b)                                          ; если последовательность возрастает
            (iter (// num 10) (% num 10) (% (// num 10) 10))
            (find-highest-seq (+ seq 1 (- b a))))))          ; 95 -> 100
 
  (if (> (count-digit seq) 8)                                ; если кол-во разрядов больше 8 (существует одна единственная строго возрастающая посл-ть)
      123456789
      (iter seq (% seq 10) (% (// seq 10) 10))))
  
(define (find-lowest-seq seq)                                ; находим меньшую последовательность
  (define (iter num a b)                                     ; num - остаточное число, a и b - первый и второй разряды числа (справа)
    (if (= 0 num)                                            ; база
        seq                                                  ; возвращаем возрастающую большую последовательность
        (if (> a b)                                          ; если последовательность возрастает
            (iter (// num 10) (% num 10) (% (// num 10) 10))
            (find-lowest-seq (- seq 1 a))                    ; 54 -> 49 
  )))
  (iter seq (% seq 10) (% (// seq 10) 10)))

(define (z2 num)
  (if (> (count-digit num) 8)                                ; для чисел, кол-во разрядностей которых больше 8, существует одна единственная строго возр полс-ть
    123456789
    (let ( (h_seq (find-highest-seq num))                    ; большая пос-ть
           (l_seq (find-lowest-seq num)))                    ; меньшая пос-ть
      (if (> (- h_seq num) (- num l_seq))                    ; находим ближайшую
        l_seq
        h_seq
))))


;--------------------------------------------------------------------------

(define (z3 num)
  (define (iter div)                  ; пробегаемся от 2 до sqrt(N)
    (if (< num (* div div))           ; база
        #t
        (if (= 0 (% num (* div div))) ; если num дважды делится на div
            #f
            (iter (+ div 1)))))       ; увеличиваем делитель
  (iter 2))

;-------------------------------------------------------------------------------------------------------------------

(define (find-min num n)                                           ; находит минимальную цифру в числе
  (if (= num 0)                                                    ; база
      n
      (if ( > n (% num 10))                 
          (find-min (// num 10) (% num 10))                        ; нашли меньшее
          (find-min (// num 10) n))))                              ; сохраняем число

(define (z4 num)
  (define min-num (find-min num 9))                                ; определяем мин цифру из num
  (define (iter num)
    (if (and (= (remainder num 10) 0) (= num 0))                   ; Проверка на нуль
        num
        (if (= (remainder num 10) min-num)
            (iter (quotient num 10))                               ; пропускаем минимальный элемент
            (+ (remainder num 10) (* 10 (iter (quotient num 10)))) ; восстанавливаем число без меньшей цифры
  )))
  (iter num))

;------------------------------------------------------------------------------

(define (z5 num)
  (cond
    [ (< num 10) #f ]                                                                           ; если одно число - горка, то #f на #t
    [ (and (< num 100) (= (% num 11) 0)) #t]                                                    ; числа 11*k < 100, для k > 0 - симметричные: 11,22,...,99
    [ (< num 100) #f]                                                                           ; остальные числа не являются симметричными
    (else
     (let ( (number (// num 10)) (a (% num 10)) (i (if (< (% (// num 10) 10) (% num 10)) 0 1))) ; находим направление по первым двум (справа) числам
       
       (symmetric-check (// number 10)                    ; num
                        (% number 10)                     ; a
                        i                                 ; i
                        (if (= i 0) 1 -1)                 ; c
                        (if (= (% number 10) a) 1 0)))))) ; cd?
; убираем пройденные числа, устанавливаем счётчик и определяем cd? (была ли смена направления)


; num - число, по которому пробегаемся
; a   - самый правый разряд числа num
; i   - направление: 0 - вниз; 1 - вверх или наравне
; с   - счетчик +1, если спускаемся, -1, если поднимаемся
; cd? - была ли смена направления: 0 - нет, 1 - да
(define (symmetric-check num a i c cd?)
  (if (= num 0)                                         ; база рекурсии
      (if (and (or (= c 0) (= c -1)) (= cd? 1)) #t #f ) ; если кол-ва чисел на спуске и подъеме равны или левая часть больше на единицу и была смена направления, то #t иначе #f
      (if (= i 0)                                       ; "спускаемся"
          (cond
            ( [< (% num 10) a]                       (symmetric-check (// num 10) (% num 10) 0 (+ c 1) cd?) ) ; "спуск" продолжается 
            ( [and (> (% num 10) a) (not (= cd? 1))] (symmetric-check (// num 10) (% num 10) 1 (- c 1) 1))    ; начался "подъём"
            ( [and (= (% num 10) a) (not (= cd? 1))] (symmetric-check (// num 10) (% num 10) 1  c      1))    ; дошли до "дна" пример: 2 2 из числа 3223
            ( [and (>= (% num 10) a) (= cd? 1)]      #f)                                                      ; была смена направления, еще раз поменялась - #f
          )
          (cond
            ( [> (% num 10) a]                       (symmetric-check (// num 10) (% num 10) 1 (- c 1) cd?))  ; "подъем" продолжается
            ( [and (< (% num 10) a) (not (= cd? 1))] (symmetric-check (// num 10) (% num 10) 0 (+ c 1) 1))    ; начали "спуск"
            ( [and (= (% num 10) a) (not (= cd? 1))] (symmetric-check (// num 10) (% num 10) 0  c      1))    ; дошли до "пика" пример: 1221
            ( [and (<= (% num 10) a) (= cd? 1)]      #f)                                                      ; была смена направления, еще раз поменялась - #f
))))



                                   